home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / combat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-29  |  45.7 KB  |  1,572 lines  |  [TEXT/KAHL]

  1. /* The combat-related actions of Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. /* Rules of combat: the attacker hits the defender ("other") unit and its
  11.    occupants, but the damage does not take effect right away.  If counter
  12.    attacks are possible in this period, the defender always does so, with
  13.    the same odds.  If the defender dies, then the attacker moves into the
  14.    cell.  If the attacker dies, nothing happens.  If both survive, then the
  15.    attacker may attempt to capture the defender. */
  16.  
  17. #include "conq.h"
  18.  
  19. static void reckon_damage_here PROTO ((int x, int y));
  20. static void capture_unit_2 PROTO ((Unit *unit, Unit *pris, PastUnit *pastpris, Side *prevside));
  21.  
  22. extern int *occdeath;
  23.  
  24. #undef  DEF_ACTION
  25. #define DEF_ACTION(name,code,args,prepfn,DOFN,checkfn,ARGDECL,doc)  \
  26.   extern int DOFN PROTO (ARGDECL);
  27.  
  28. #include "action.def"
  29.  
  30. int maxudetonaterange = -1;
  31.  
  32. int maxtdetonaterange = -1;
  33.  
  34. int max_detonate_on_approach_range = -1;
  35.  
  36. /* Remember what the main units involved are, so display is handled relative
  37.    to them and not to any occupants. */
  38.  
  39. Unit *amain, *omain;
  40.  
  41. /* ... but the data is saved anyway, for message generation. */
  42.  
  43. int *occhits = NULL;
  44. int *occkills = NULL;
  45.  
  46. int numsoundplays;
  47.  
  48. /* Attack action. */
  49.  
  50. /* This is an attack on a given unit at a given level of commitment. */
  51.  
  52. int
  53. prep_attack_action(unit, unit2, defender, n)
  54. Unit *unit, *unit2, *defender;
  55. int n;
  56. {
  57.     if (unit == NULL || unit->act == NULL)
  58.       return FALSE;
  59.     if (unit2 == NULL)
  60.       return FALSE;
  61.     unit->act->nextaction.type = A_ATTACK;
  62.     unit->act->nextaction.args[0] = defender->id;
  63.     unit->act->nextaction.args[1] = n;
  64.     unit->act->nextaction.actee = unit2->id;
  65.     return TRUE;
  66. }
  67.  
  68. int
  69. do_attack_action(unit, unit2, defender, n)
  70. Unit *unit, *unit2, *defender;
  71. int n;
  72. {
  73.     int u = unit->type, u2 = unit2->type, u3 = defender->type;
  74.     int withdrawchance, surrenderchance;
  75.  
  76.     /* Defender might be a type that can sneak away to avoid attack. */
  77.     withdrawchance = uu_withdraw_per_attack(u2, u3);
  78.     if (withdrawchance > 0) {
  79.     if (probability(withdrawchance)) {
  80.         if (retreat_unit(defender, unit2)) {
  81.             if (alive(unit))
  82.               use_up_acp(unit, uu_acp_to_attack(u2, u3));
  83.         return A_ANY_DONE;
  84.         }
  85.     }
  86.     }
  87.     /* Defender might instead choose to surrender right off. */
  88.     surrenderchance = uu_surrender_per_attack(u2, u3);
  89.     if (surrenderchance > 0) {
  90.     if (probability(surrenderchance)) {
  91.         capture_unit(unit2, defender);
  92.         if (alive(unit))
  93.           use_up_acp(unit, uu_acp_to_attack(u2, u3));
  94.         return A_ANY_DONE;
  95.     }
  96.     }
  97.     /* Carry out a normal attack. */
  98.     one_attack(unit, defender);
  99.     if (alive(unit)) use_up_acp(unit, uu_acp_to_attack(u2, u3));
  100.     /* The defender in an attack has to take time to defend itself. */
  101.     if (alive(defender)) use_up_acp(defender, uu_acp_to_defend(u2, u3));
  102.     return A_ANY_DONE;
  103. }
  104.  
  105. int
  106. check_attack_action(unit, unit2, defender, n)
  107. Unit *unit, *unit2, *defender;
  108. int n;
  109. {
  110.     int u, u2, u3, acp, u2x, u2y, dfx, dfy, dist, m;
  111.  
  112.     if (!in_play(unit))
  113.       return A_ANY_ERROR;
  114.     if (!in_play(unit2))
  115.       return A_ANY_ERROR;
  116.     if (!in_play(defender))
  117.       return A_ANY_ERROR;
  118.     /* We can't attack ourselves. */
  119.     if (unit2 == defender)
  120.       return A_ANY_ERROR;
  121.     if (unit2->side != NULL && unit2->side == defender->side)
  122.       return A_ANY_ERROR;
  123.     u = unit->type;
  124.     u2 = unit2->type;
  125.     u3 = defender->type;
  126.     acp = uu_acp_to_attack(u2, u3);
  127.     if (acp < 1)
  128.       return A_ANY_CANNOT_DO;
  129.     if (!has_enough_acp(unit, acp))
  130.       return A_ANY_NO_ACP;
  131.     /* Check whether we can attack from inside a transport. */
  132.     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
  133.       return A_ANY_ERROR;
  134.     u2x = unit2->x;  u2y = unit2->y;
  135.     dfx = defender->x;  dfy = defender->y;
  136.     dist = distance(u2x, u2y, dfx, dfy);
  137.     if (dist < uu_attack_range_min(u2, u3))
  138.       return A_ANY_TOO_NEAR;
  139.     if (dist > uu_attack_range(u2, u3))
  140.       return A_ANY_TOO_FAR;
  141.     if (uu_hit(u2, u3) <= 0)
  142.       return A_ANY_ERROR;
  143.     /* We have to have a minimum level of supply to be able to attack. */
  144.     for_all_material_types(m) {
  145.     if (unit2->supply[m] < um_to_fight(u2, m))
  146.       return A_ANY_NO_MATERIAL;
  147.     }
  148.     /* (should prorate ammo needs by intensity of attack) */
  149.     if (!enough_ammo(unit2, defender))
  150.       return A_ANY_ERROR;
  151.     /* Allow attacks even if zero damage, this amounts to "harassment". */
  152.     return A_ANY_OK;
  153. }
  154.  
  155. /* Overrun action. */
  156.  
  157. /* Overrun is an attempt to occupy a given cell that may include attempts
  158.    to attack and/or capture any units in the way. */
  159.  
  160. int
  161. prep_overrun_action(unit, unit2, x, y, z, n)
  162. Unit *unit, *unit2;
  163. int x, y, z, n;
  164. {
  165.     if (unit == NULL || unit->act == NULL)
  166.       return FALSE;
  167.     if (unit2 == NULL)
  168.       return FALSE;
  169.     unit->act->nextaction.type = A_OVERRUN;
  170.     unit->act->nextaction.args[0] = x;
  171.     unit->act->nextaction.args[1] = y;
  172.     unit->act->nextaction.args[2] = z;
  173.     unit->act->nextaction.args[3] = n;
  174.     unit->act->nextaction.actee = unit2->id;
  175.     return TRUE;
  176. }
  177.  
  178. int
  179. do_overrun_action(unit, unit2, x, y, z, n)
  180. Unit *unit, *unit2;
  181. int x, y, z, n;
  182. {
  183.     int u, u2, u3, cleared = TRUE, cost, rslt;
  184.     Unit *defender;
  185.  
  186.     u = unit->type;
  187.     u2 = unit2->type;
  188.     /* Attack every defender in turn. */
  189.     for_all_stack(x, y, defender) {
  190.     u3 = defender->type;
  191.     /* Don't attack any of our buddies. */
  192.     if (unit2->side == defender->side)
  193.       continue;
  194.     one_attack(unit2, defender);
  195.     if (alive(unit))
  196.       use_up_acp(unit, uu_acp_to_attack(u2, u3));
  197.     /* The target of an attack has to take time to defend itself. */
  198.     if (alive(defender)) {
  199.         use_up_acp(defender, uu_acp_to_defend(u, u3));
  200.         cleared = FALSE;
  201.     }
  202.     }
  203.     if (alive(unit2) && cleared) {
  204.     /* Try to enter the cleared cell now - might still have
  205.        friendlies filling it up already, so check first. */
  206.     if (can_occupy_cell(unit2, x, y)) {
  207.         cost = move_unit(unit2, x, y);
  208.         /* Note that we'll say the action succeeded even if
  209.            the cell did not have enough room for us to actually
  210.            be in it, which is a little weird. */
  211.     }
  212.     rslt = A_OVERRUN_SUCCEEDED;
  213.     } else {
  214.     rslt = A_OVERRUN_FAILED;
  215.     }
  216.     return rslt;
  217. }
  218.  
  219. int
  220. check_overrun_action(unit, unit2, x, y, z, n)
  221. Unit *unit, *unit2;
  222. int x, y, z, n;
  223. {
  224.     int u, u2, u2x, u2y, u2z, u3, totcost, speed, mpavail, m;
  225.     Unit *defender;
  226.  
  227.     if (!in_play(unit))
  228.       return A_ANY_ERROR;
  229.     if (!in_play(unit2))
  230.       return A_ANY_ERROR;
  231.     if (!inside_area(x, y))
  232.       return A_ANY_ERROR;
  233.     if (n == 0)
  234.       return A_ANY_ERROR;
  235.     u = unit->type;
  236.     u2 = unit2->type;
  237.     /* (should think about this some more - overrunning into a cell with no
  238.         resistance should work perhaps, even for noncombat units) */
  239.     if (!type_can_attack(u))
  240.       return A_ANY_CANNOT_DO;
  241.     if (!has_enough_acp(unit, 1))
  242.       return A_ANY_NO_ACP;
  243.     /* Check whether we can attack from inside a transport. */
  244.     /* (although this might be legit if unit is assumed to leave transport first) */
  245.     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
  246.       return A_ANY_ERROR;
  247.     u2x = unit2->x;  u2y = unit2->y;  u2z = unit2->z;
  248.     /* We have to be in the same cell or an adjacent one. */
  249.     if (!between(0, distance(u2x, u2y, x, y), 1))
  250.       return A_ANY_TOO_FAR;
  251.     /* Now start looking at the move costs. */
  252.     u3 = (unit2->transport ? unit2->transport->type : NONUTYPE);
  253.     totcost = total_move_cost(u2, u3, u2x, u2y, u2z, x, y, u2z);
  254.     speed = unit_speed(unit2, x, y);
  255.     mpavail = (unit->act->acp * speed) / 100;
  256.     /* Zero mp always disallows movement, unless intra-cell. */
  257.     if (mpavail <= 0 && !(u2x == x && u2y == y && u2z == u2z))
  258.       return A_MOVE_NO_MP;
  259.     /* The free mp might get us enough moves, so add it before comparing. */
  260.     if (mpavail + u_free_mp(u2) < totcost)
  261.       return A_MOVE_NO_MP;
  262.     /* We have to have a minimum level of supply to be able to attack. */
  263.     for_all_material_types(m) {
  264.     if (unit2->supply[m] < um_to_fight(u2, m))
  265.       return A_ANY_NO_MATERIAL;
  266.     }
  267.     for_all_stack(x, y, defender) {
  268.     /* (should test if units here can be attacked en masse) */
  269.         /* (should prorate ammo needs by intensity of overrun) */
  270.         if (!enough_ammo(unit2, defender))
  271.           return A_ANY_NO_MATERIAL;
  272.     }
  273.     return A_ANY_OK;
  274. }
  275.  
  276. /* Return true if the attacker defeated the defender, and can therefore
  277.    try to move into the defender's old position. */
  278.  
  279. int
  280. one_attack(atker, defender)
  281. Unit *atker, *defender;
  282. {
  283.     int u, ax = atker->x, ay = atker->y, ox = defender->x, oy = defender->y;
  284.     Side *as = atker->side, *os = defender->side;
  285.  
  286.     amain = atker;  omain = defender;
  287.     if (occhits == NULL)
  288.       occhits = (int *) xmalloc(numutypes * sizeof(int));
  289.     if (occkills == NULL)
  290.       occkills = (int *) xmalloc(numutypes * sizeof(int));
  291.     for_all_unit_types(u)
  292.       occhits[u] = occkills[u] = 0;
  293.     attack_unit(atker, defender);
  294.     /* (this test should account for counterattacking occupants too,
  295.        handle them in here somehow) */
  296.     if (1 /* uu_counter_strength(defender->type, atker->type) > 0 */) {
  297.     attack_unit(defender, atker);
  298.     }
  299.     reckon_damage();
  300.     see_exact(as, ax, ay);
  301.     see_exact(as, ox, oy);
  302.     see_exact(os, ax, ay);
  303.     see_exact(os, ox, oy);
  304.     update_cell_display(as, ax, ay, TRUE);
  305.     update_cell_display(as, ox, oy, TRUE);
  306.     update_cell_display(os, ax, ay, TRUE);
  307.     update_cell_display(os, ox, oy, TRUE);
  308.     all_see_cell(ax, ay);
  309.     all_see_cell(ox, oy);
  310.     attempt_to_capture_unit(atker, defender);
  311.     return (alive(atker) && unit_at(ox, oy) == NULL);
  312. }
  313.  
  314. /* Fire-at action. */
  315.  
  316. /* Shooting at a given unit. */
  317.  
  318. int
  319. prep_fire_at_action(unit, unit2, defender, m)
  320. Unit *unit, *unit2, *defender;
  321. int m;
  322. {
  323.     if (unit == NULL || unit->act == NULL)
  324.       return FALSE;
  325.     if (unit2 == NULL)
  326.       return FALSE;
  327.     unit->act->nextaction.type = A_FIRE_AT;
  328.     unit->act->nextaction.args[0] = defender->id;
  329.     unit->act->nextaction.args[1] = m;
  330.     unit->act->nextaction.actee = unit2->id;
  331.     return TRUE;
  332. }
  333.  
  334. int
  335. do_fire_at_action(unit, unit2, defender, m)
  336. Unit *unit, *unit2, *defender;
  337. int m;
  338. {
  339.     int ux = unit->x, uy = unit->y, ox, oy, oz, u;
  340.  
  341.     update_fire_at_display(unit->side, unit, defender, m, TRUE);
  342.     update_fire_at_display(defender->side, unit, defender, m, TRUE);
  343.     ox = defender->x;  oy = defender->y;  oz = defender->z;
  344.     amain = unit;  omain = defender;
  345.     if (occhits == NULL)
  346.       occhits = (int *) xmalloc(numutypes * sizeof(int));
  347.     if (occkills == NULL)
  348.       occkills = (int *) xmalloc(numutypes * sizeof(int));
  349.     for_all_unit_types(u)
  350.       occhits[u] = occkills[u] = 0;
  351.     fire_on_unit(unit, defender);
  352.     reckon_damage();
  353.     if (alive(unit))
  354.       use_up_acp(unit, u_acp_to_fire(unit2->type));
  355.     /*    if (alive(defender)) use_up_acp(defender, 1); */
  356.     /* Each side sees what happened to its own unit. */
  357.     update_unit_display(unit2->side, unit2, TRUE);
  358.     if (unit != unit2)
  359.       update_unit_display(unit->side, unit, TRUE);
  360.     update_unit_display(defender->side, defender, TRUE);
  361.     /* The attacking side also sees the remote cell. */
  362.     update_cell_display(unit2->side, ox, oy, TRUE);
  363.     update_cell_display(defender->side, ox, oy, TRUE);
  364.     /* Victim might see something in attacker's cell. */
  365.     update_cell_display(defender->side, ux, uy, TRUE);
  366.     /* Actually, everybody might be seeing the combat. */
  367.     all_see_cell(ux, uy);
  368.     all_see_cell(ox, oy);
  369.     /* Always expend the ammo (but only if m is a valid mtype). */
  370.     return A_ANY_DONE;
  371. }
  372.  
  373. /* Test a fire action for plausibility. */
  374.  
  375. int
  376. check_fire_at_action(unit, unit2, unit3, m)
  377. Unit *unit, *unit2, *unit3;
  378. int m;
  379. {
  380.     int u, u2, u3, ux, uy, uz, acp, dist, m2;
  381.  
  382.     if (!in_play(unit))
  383.       return A_ANY_ERROR;
  384.     if (!in_play(unit2))
  385.       return A_ANY_ERROR;
  386.     if (!in_play(unit3))
  387.       return A_ANY_ERROR;
  388.     /* We can't attack ourselves. */
  389.     if (unit2 == unit3)
  390.       return A_ANY_ERROR;
  391.     u = unit->type; u2 = unit2->type;  u3 = unit3->type;
  392.     ux = unit->x;  uy = unit->y;  uz = unit->z;
  393.     acp = u_acp_to_fire(u2);
  394.     if (acp < 1)
  395.       return A_ANY_CANNOT_DO;
  396.     if (!has_enough_acp(unit, acp))
  397.       return A_ANY_NO_ACP;
  398.     /* Check whether we can attack from inside a transport. */
  399.     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
  400.       return A_ANY_ERROR;
  401.     /* Check that target is in range. */
  402.     dist = distance(ux, uy, unit3->x, unit3->y);
  403.     if (dist > u_range(u2))
  404.       return A_FIRE_AT_TOO_FAR;
  405.     if (dist < u_range_min(u2))
  406.       return A_FIRE_AT_TOO_NEAR;
  407.     /* (should allow some self-attacks sometimes?) */
  408.     if (unit2->side != NULL && unit2->side == unit3->side)
  409.       return A_ANY_ERROR;
  410.     /* Check intervening elevations. */
  411.     if (found_blocking_elevation(u2, ux, uy, uz, u3, unit3->x, unit3->y, unit3->z))
  412.       return A_ANY_ERROR;
  413.     /* We have to have a minimum level of supply to be able to attack. */
  414.     for_all_material_types(m2) {
  415.     if (unit2->supply[m2] < um_to_fight(u2, m2))
  416.       return A_ANY_NO_MATERIAL;
  417.     }
  418.     /* Check for enough of right kind of ammo. */
  419.     if (is_material_type(m)) {
  420.         if (unit->supply[m] == 0)
  421.           return A_ANY_NO_MATERIAL;
  422.     } else {
  423.         if (!enough_ammo(unit2, unit3))
  424.           return A_ANY_NO_MATERIAL;
  425.     }
  426.     return A_ANY_OK;
  427. }
  428.  
  429. /* Fire-into action. */
  430.  
  431. /* Shooting at a given location. */
  432.  
  433. int
  434. prep_fire_into_action(unit, unit2, x, y, z, m)
  435. Unit *unit, *unit2;
  436. int x, y, z, m;
  437. {
  438.     if (unit == NULL || unit->act == NULL)
  439.       return FALSE;
  440.     if (unit2 == NULL)
  441.       return FALSE;
  442.     unit->act->nextaction.type = A_FIRE_INTO;
  443.     unit->act->nextaction.args[0] = x;
  444.     unit->act->nextaction.args[1] = y;
  445.     unit->act->nextaction.args[2] = z;
  446.     unit->act->nextaction.args[3] = m;
  447.     unit->act->nextaction.actee = unit2->id;
  448.     return TRUE;
  449. }
  450.  
  451. /* One can always shoot, if the cell is visible, but there might not
  452.    not be anything to hit!  No counterattacks when shooting, and the
  453.    results might not be visible to the shooter. */
  454.  
  455. int
  456. do_fire_into_action(unit, unit2, x, y, z, m)
  457. Unit *unit, *unit2;
  458. int x, y, z, m;
  459. {
  460.     int ux = unit->x, uy = unit->y, ox, oy, oz, u;
  461.     SideMask sidemask;
  462.     Unit *other;
  463.     Side *side;
  464.  
  465.     /* Show the firing unit doing its attack. */
  466.     update_fire_into_display(unit->side, unit2, x, y, z, m, TRUE);
  467.     /* Make up the list of sides that will see the incoming fire. */
  468.     sidemask = NOSIDES;
  469.     for_all_stack(x, y, other) {
  470.     if (other->side)
  471.       sidemask = add_side_to_set(other->side, sidemask);
  472.     }
  473.     for_all_sides(side) {
  474.     if (side_in_set(side, sidemask))
  475.           update_fire_into_display(side, unit2, x, y, z, m, TRUE);
  476.     }
  477.     /* If any units at target, hit them. */
  478.     for_all_stack(x, y, other) {
  479.     ox = other->x;  oy = other->y;  oz = other->z;
  480.     amain = unit;  omain = other;
  481.     if (occhits == NULL)
  482.       occhits = (int *) xmalloc(numutypes * sizeof(int));
  483.     if (occkills == NULL)
  484.       occkills = (int *) xmalloc(numutypes * sizeof(int));
  485.     for_all_unit_types(u)
  486.       occhits[u] = occkills[u] = 0;
  487.     fire_on_unit(unit2, other);
  488.     reckon_damage();
  489.     /* Each side sees what happened to its unit that is being hit. */
  490.     update_unit_display(other->side, other, TRUE);
  491.     /* The attacking side also sees the remote cell. */
  492.     update_cell_display(unit->side, ox, oy, TRUE);
  493.     update_cell_display(other->side, ox, oy, TRUE);
  494.     /* Victim might see something in attacker's cell. */
  495.     update_cell_display(other->side, ux, uy, TRUE);
  496.     /* Actually, everybody might be seeing the combat. */
  497.     all_see_cell(ux, uy);
  498.     all_see_cell(ox, oy);
  499.     /* don't take moves though! */
  500.     }
  501.     /* Firing side gets just one update. */
  502.     update_unit_display(unit2->side, unit2, TRUE);
  503.     if (unit != unit2)
  504.       update_unit_display(unit->side, unit, TRUE);
  505.     if (alive(unit))
  506.       use_up_acp(unit, u_acp_to_fire(unit2->type));
  507.     /* Always expend the ammo (but only if m is a valid material). */
  508.     /* We're always "successful", even though the bombardment may have
  509.        had little or no actual effect. */
  510.     return A_ANY_DONE;
  511. }
  512.  
  513. /* Test a shoot action for plausibility. */
  514.  
  515. int
  516. check_fire_into_action(unit, unit2, x, y, z, m)
  517. Unit *unit, *unit2;
  518. int x, y, z, m;
  519. {
  520.     int u, u2, u2x, u2y, u2z, acp, dist, m2;
  521.  
  522.     if (!in_play(unit))
  523.       return A_ANY_ERROR;
  524.     if (!in_play(unit2))
  525.       return A_ANY_ERROR;
  526.     u2x = unit2->x;  u2y = unit2->y;  u2z = unit2->z;
  527.     /* Check that target location is meaningful. */
  528.     if (!inside_area(x, y))
  529.       return A_FIRE_INTO_OUTSIDE_WORLD;
  530.     u = unit->type;
  531.     u2 = unit2->type;
  532.     acp = u_acp_to_fire(u2);
  533.     if (acp < 1)
  534.       return A_ANY_CANNOT_DO;
  535.     if (!has_enough_acp(unit, acp))
  536.       return A_ANY_NO_ACP;
  537.     /* Check whether we can attack from inside a transport. */
  538.     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
  539.       return A_ANY_ERROR;
  540.     /* Check that target is in range. */
  541.     dist = distance(u2x, u2y, x, y);
  542.     if (dist > u_range(u2))
  543.       return A_FIRE_INTO_TOO_FAR;
  544.     if (dist < u_range_min(u2))
  545.       return A_FIRE_INTO_TOO_NEAR;
  546.     /* Check intervening elevations. */
  547.     if (found_blocking_elevation(u2, u2x, u2y, u2z, NONUTYPE, x, y, z))
  548.       return A_ANY_ERROR;
  549.     /* We have to have a minimum level of supply to be able to attack. */
  550.     for_all_material_types(m2) {
  551.     if (unit2->supply[m2] < um_to_fight(u2, m2))
  552.       return A_ANY_NO_MATERIAL;
  553.     }
  554.     /* Check for enough of right kind of ammo. */
  555.     if (is_material_type(m)) {
  556.         if (unit->supply[m] == 0)
  557.           return A_ANY_NO_MATERIAL;
  558.     } else {
  559.         /* should just assume amount is appropriate? */
  560.     }
  561.     return A_ANY_OK;
  562. }
  563.  
  564. int
  565. found_blocking_elevation(u, ux, uy, uz, u2, u2x, u2y, u2z)
  566. int u, ux, uy, uz, u2, u2x, u2y, u2z;
  567. {
  568. /*    int maxrise = u_elev_at_max_range(u); */
  569.  
  570.     if (world_is_flat())
  571.       return FALSE;
  572.     /* Adjacent cells can't be screened by elevation. */
  573.     /* (should accommodate possibility that target is at top of
  574.        cliff in adj and back away from its edge, thus screened) */
  575.     if (distance(ux, uy, u2x, u2y) <= 1)
  576.       return FALSE;
  577.     /* (should add scan of path) */
  578.     return FALSE;
  579. }
  580.  
  581. void
  582. fire_on_unit(atker, other)
  583. Unit *atker, *other;
  584. {
  585.     int m, dist = distance(atker->x, atker->y, other->x, other->y);
  586.  
  587.     /* this should be an event needing a response */
  588. /*    wake_unit(other, TRUE, WAKEENEMY, atker);  */
  589.     if (alive(atker) && alive(other)) {
  590.     if (enough_ammo(atker, other)) {
  591.         maybe_hit_unit(atker, other, (dist > u_hit_falloff_range(atker->type)));
  592.         for_all_material_types(m) {
  593.         if (um_hitby(other->type, m) > 0) {
  594.             atker->supply[m] -= um_consumption_per_attack(atker->type, m);
  595.         }
  596.         }
  597.         /* The *victim* can lose acp. */
  598.         use_up_acp(other, uu_acp_to_be_fired_on(other->type, atker->type));
  599.     }
  600.     }
  601. }
  602.  
  603. /* Test to see if enough ammo is available to make the attack.
  604.    Need enough of *all* types - semi-bogus but too complicated otherwise? */
  605.  
  606. int
  607. enough_ammo(unit, other)
  608. Unit *unit, *other;
  609. {
  610.     int m;
  611.  
  612.     for_all_material_types(m) {
  613.     if (um_hitby(other->type, m) > 0 &&
  614.         unit->supply[m] < um_consumption_per_attack(unit->type, m))
  615.       return FALSE;
  616.     }
  617.     return TRUE;
  618. }
  619.  
  620. /* Single attack, no counterattack.  Check and use ammo - usage independent
  621.    of outcome, but types used depend on unit types involved. */
  622.  
  623. void
  624. attack_unit(atker, other)
  625. Unit *atker, *other;
  626. {
  627.     int m;
  628.  
  629.     /* this should be an event needing a response */
  630. /*    wake_unit(other, TRUE, WAKEENEMY, atker);  */
  631.     if (alive(atker) && alive(other)) {
  632.     if (enough_ammo(atker, other)) {
  633.         maybe_hit_unit(atker, other, FALSE);
  634.         for_all_material_types(m) {
  635.         if (um_hitby(other->type, m) > 0) {
  636.             atker->supply[m] -= um_consumption_per_attack(atker->type, m);
  637.         }
  638.         }
  639.     }
  640.     }
  641. }
  642.  
  643. /* Make a single hit and maybe hit some passengers also.  Power of hit
  644.    is constant, but chance is affected by terrain, quality,
  645.    and occupants' protective abilities.  If a hit is successful, it may
  646.    have consequences on the defender's occupants, but limited by the
  647.    protection that the transport provides. */
  648.  
  649. void
  650. maybe_hit_unit(atker, other, fallsoff)
  651. int fallsoff;
  652. Unit *atker, *other;
  653. {
  654.     int chance, t, hit = 0, a = atker->type, o = other->type;
  655.     int cxpeffect, cxpmax, effect, prot;
  656.     int dist, disthit, rangedelta, hitdelta, rangeamt;
  657.     int dmgspec;
  658.     int btype;
  659.     Unit *occ, *unit2;
  660.     Side *as = atker->side, *os = other->side, *side3;
  661.     
  662.     Dprintf("%s tries to hit %s", unit_desig(atker), unit_desig(other));
  663.     chance = uu_hit(a, o);
  664.     /* Combat experience tends to raise the hit chance, so do that first. */
  665.     cxpmax = u_cxp_max(a);
  666.     if (cxpmax > 0 && atker->cxp > 0) {
  667.     cxpeffect = uu_hit_cxp(a, o);
  668.     if (cxpeffect != 100) {
  669.         effect = 100 + (atker->cxp * (cxpeffect - 100)) / cxpmax;
  670.         chance = (chance * effect) / 100;
  671.     }
  672.     }
  673.     /* (should modify due to cxp of defender too) */
  674.     /* Account for terrain effects. */
  675.     t = terrain_at(atker->x, atker->y);
  676.     chance = (chance * ut_attack_terrain_effect(a, t)) / 100;
  677.     t = terrain_at(other->x, other->y);
  678.     chance = (chance * ut_defend_terrain_effect(o, t)) / 100;
  679.     /* Account for protective units nearby. */
  680.     for_all_occupants(other, occ) {
  681.     if (in_play(occ) && completed(occ)) {
  682.         prot = uu_protection(occ->type, o);
  683.         if (prot != 100)
  684.           chance = (chance * prot) / 100;
  685.     }
  686.     }
  687.     if (other->transport
  688.     && in_play(other->transport)
  689.     && completed(other->transport)) {
  690.     prot = uu_protection(other->transport->type, o);
  691.     if (prot != 100)
  692.       chance = (chance * prot) / 100;
  693.     }
  694.     for_all_stack(other->x, other->y, unit2) {
  695.     if (unit2 != other
  696.         && in_play(unit2)
  697.         && completed(unit2)
  698.         && unit2->side == other->side) {
  699.         prot = uu_stack_protection(unit2->type, o);
  700.         if (prot != 100)
  701.           chance = (chance * prot) / 100;
  702.     }
  703.     }
  704.     if (fallsoff) {
  705.     dist = distance(atker->x, atker->y, other->x, other->y);
  706.         disthit = uu_hit_max_range_effect(a, o);
  707.         rangedelta = u_range(a) - u_hit_falloff_range(a);
  708.         rangeamt = dist - u_hit_falloff_range(a);
  709.         hitdelta = uu_hit(a, o) - disthit;
  710.         chance = uu_hit(a, o)
  711.       - ((uu_hit(a, o) - disthit) * rangeamt) / rangedelta;
  712.     }
  713.     Dprintf(", probability of hit is %d%%", chance);
  714.     /* Compute the hit itself. */
  715.     if (probability(chance)) {
  716.         dmgspec = uu_damage(a, o);
  717.         /* Account for attacker's experience. */
  718.     if (cxpmax > 0 && atker->cxp > 0) {
  719.         cxpeffect = uu_damage_cxp(a, o);
  720.         if (cxpeffect != 100) {
  721.         effect = 100 + (atker->cxp * (cxpeffect - 100)) / cxpmax;
  722.         dmgspec = multiply_dice(dmgspec, effect);
  723.         }
  724.     }
  725.     hit = roll_dice(dmgspec);
  726.     }
  727.     if (hit > 0) {
  728.         Dprintf(", damage will be %d hp", hit);
  729.     } else {
  730.         Dprintf(", missed");
  731.     }
  732.     /* (should record a raw statistic?) */
  733.     /* Ablation is a chance for occupants or stack to take part of a hit themselves. */
  734.     if (hit > 0) {
  735.     /* (should decide how ablation computed) */
  736.     }
  737.     if (hit > 0) {
  738.     chance = uu_retreat_chance(a, o);
  739.     /* (should adjust chance by morale etc) */
  740.     if (probability(chance)) {
  741.         if (retreat_unit(other, atker)) {
  742.         notify(as, "%s runs away!", unit_handle(as, other));
  743.         notify(os, "%s runs away!", unit_handle(os, other));
  744.         /* (what about other onlookers?) */
  745.         hit = 0; /* should only be reduced hit, may still be > 0 */
  746.         }
  747.     }
  748.     }
  749.     hit_unit(other, hit, atker);
  750.     for_all_sides(side3) {
  751.         if (active_display(side3)) {
  752.             if (g_see_all()
  753.                 || (side3 == atker->side || side3 == other->side)) {
  754.         btype = ((hit >= other->hp) ? movie_death :
  755.              ((hit > 0) ? movie_hit : movie_miss));
  756.         schedule_movie(side3, btype, other);
  757.             }
  758.         }
  759.     }
  760.     Dprintf("\n");
  761.     /* Recurse into occupants, maybe hit them too.  */
  762.     for_all_occupants(other, occ) {
  763.     if (probability(100 - uu_protection(o, occ->type))) {
  764.         maybe_hit_unit(atker, occ, fallsoff);
  765.     }
  766.     }
  767.     /* We get combat experience only if there could have been some damage. */
  768.     if (chance > 0) {
  769.         if (atker->cxp < u_cxp_max(a))
  770.           atker->cxp += uu_cxp_per_combat(a, o);
  771.         if (other->cxp < u_cxp_max(o))
  772.           other->cxp += uu_cxp_per_combat(o, a);
  773.         /* (should occupants get cxp also?) */
  774.     }
  775. }
  776.  
  777. /* Do the hit itself. */
  778.  
  779. void
  780. hit_unit(unit, hit, atker)
  781. Unit *unit, *atker;
  782. int hit;
  783. {
  784.     int u = unit->type, hpmin;
  785.  
  786.     /* Some units might detonate automatically upon being hit. */
  787.     if (hit > 0
  788.         && atker != NULL
  789.         && probability(uu_detonate_on_hit(u, atker->type))) {
  790.         detonate_unit(unit, unit->x, unit->y, unit->z);
  791.         /* If the detonating unit still exists, then continue
  792.            on to normal damage computation. */
  793.     }
  794.     /* Record the loss of hp. */
  795.     unit->hp2 -= hit;
  796.     /* Attacker might not be able to do any more damage.  Note that the
  797.        positioning of this code is such that all the usual side effects
  798.        of combat happen, but the victim doesn't get any more worse off
  799.        than it is already. */
  800.     if (atker != NULL) {
  801.     hpmin = uu_hp_min(atker->type, u);
  802.     if (hpmin > 0 && hpmin > unit->hp2) {
  803.         unit->hp2 = hpmin;
  804.     }
  805.     }
  806.     /* Maybe record for statistical analysis. */
  807.     /* (this is only useful if code always goes through here - is that true?) */
  808.     if (atker != NULL && atker->side != NULL) {
  809.     if (atker->side->atkstats[atker->type] == NULL)
  810.       atker->side->atkstats[atker->type] = (long *) xmalloc(numutypes * sizeof(long));
  811.     if (atker->side->hitstats[atker->type] == NULL)
  812.       atker->side->hitstats[atker->type] = (long *) xmalloc(numutypes * sizeof(long));
  813.     ++((atker->side->atkstats[atker->type])[u]);
  814.     (atker->side->hitstats[atker->type])[u] += hit;
  815.     }
  816.     /* Some units detonate automatically just before dying. */
  817.     if (hit > 0
  818.         && unit->hp2 <= 0
  819.         && probability(u_detonate_on_death(u))) {
  820.     detonate_unit(unit, unit->x, unit->y, unit->z);
  821.     }
  822. }
  823.  
  824. /* Hits on the main units have to be done later, so that mutual
  825.    destruction works properly.  This function also does all the notifying. */
  826.  
  827. /* (Only the main units of a cell rate messages, occupants' fates are */
  828. /* summarized briefly.) */
  829.  
  830. /* (What if occupants change type when killed, but transport vanishes?) */
  831.  
  832. void
  833. reckon_damage()
  834. {
  835.     int i;
  836.     Side *as = amain->side, *os = omain->side;
  837.     char hitbuf[BUFSIZE], killbuf[BUFSIZE];
  838.     char aabuf[BUFSIZE], aobuf[BUFSIZE], oabuf[BUFSIZE], oobuf[BUFSIZE];
  839.  
  840.     /* Entertain everybody. */
  841.     play_movies(ALLSIDES);
  842.     strcpy(aabuf, unit_handle(as, amain));
  843.     strcpy(aobuf, unit_handle(as, omain));
  844.     strcpy(oabuf, unit_handle(os, amain));
  845.     strcpy(oobuf, unit_handle(os, omain));
  846.     if (omain->hp2 <= 0) {
  847.     notify(as, "%s %s %s!", aabuf, "destroys", aobuf);
  848.     notify(os, "%s %s %s!", oabuf, "destroys", oobuf);
  849.     for_all_unit_types(i) occkills[i] += (occdeath ? occdeath[i] : 0);
  850.     } else if (amain->hp2 < amain->hp) {
  851.     notify(as, "%s hits %s!", aabuf, aobuf);
  852.     notify(os, "%s hits %s!", oabuf, oobuf);
  853.     } else {
  854.     /* messages about missing not too useful */
  855.     }
  856.     summarize_units(hitbuf, occhits);
  857.     summarize_units(killbuf, occkills);
  858.     if (strlen(hitbuf) > 0) {
  859.     if (strlen(killbuf) > 0) {
  860.         notify(as, "   (Also hit%s, killed%s)", hitbuf, killbuf);
  861.         notify(os, "   (%s hurt, %s killed)", hitbuf, killbuf);
  862.     } else {
  863.         notify(as, "   (Also hit%s)", hitbuf);
  864.         notify(os, "   (%s hurt)", hitbuf);
  865.     }
  866.     } else {
  867.     if (strlen(killbuf) > 0) {
  868.         notify(as, "   (Also killed%s)", killbuf);
  869.         notify(os, "   (%s killed)", killbuf);
  870.     }
  871.     }
  872.     if (amain->hp2 <= 0) {
  873.     notify(as, "%s %s %s!", aobuf, "wrecks", aabuf);
  874.     notify(os, "%s %s %s!", oobuf, "wrecks", oabuf);
  875.     } else if (amain->hp2 < amain->hp) {
  876.     notify(as, "%s hits %s!", aobuf, aabuf);
  877.     notify(os, "%s hits %s!", oobuf, oabuf);
  878.     } else {
  879.     /* messages about missing not too useful */
  880.     }
  881.     damage_unit(omain);
  882.     damage_unit(amain);
  883. }
  884.  
  885. static void
  886. reckon_damage_here(x, y)
  887. int x, y;
  888. {
  889.     Unit *unit;
  890.  
  891.     for_all_stack(x, y, unit) {
  892.     damage_unit(unit);
  893.     }
  894. }
  895.  
  896. void
  897. reckon_damage_around(x, y, r)
  898. int x, y, r;
  899. {
  900.     if (r > 0) {
  901.     apply_to_area(x, y, r, reckon_damage_here);
  902.     } else {
  903.     reckon_damage_here(x, y);
  904.     }
  905. }
  906.  
  907. /* Make the intended damage become real, and do any
  908.    consequences. */
  909.  
  910. void
  911. damage_unit(unit)
  912. Unit *unit;
  913. {
  914.     int newacp, observers;
  915.     Obj *dameff;
  916.     Unit *occ;
  917.  
  918.     /* Process all the occupants first. */
  919.     for_all_occupants(unit, occ) {
  920.     damage_unit(occ);
  921.     }
  922.     /* If no damage was recorded, just return. */
  923.     if (unit->hp2 == unit->hp)
  924.       return;
  925.     /* If unit is to die, do the consequences. */
  926.     if (unit->hp2 <= 0) {
  927.     if (u_wrecked_type(unit->type) == NONUTYPE) {
  928.         /* (should let occupants escape now?) */
  929.         kill_unit(unit, H_UNIT_KILLED);
  930.     } else {
  931.         change_unit_type(unit, u_wrecked_type(unit->type), H_UNIT_WRECKED);
  932.         /* Restore to default hp for the new type. */
  933.         unit->hp = unit->hp2 = u_hp(unit->type);
  934.         /* Get rid of occupants if overfull. */
  935.         eject_excess_occupants(unit);
  936.         /* (should report that unit was wrecked) */
  937.     }
  938.     } else {
  939.     record_event(H_UNIT_DAMAGED, add_side_to_set(unit->side, NOSIDES),
  940.              unit->id, unit->hp, unit->hp2);
  941.     /* Change the unit's hp. */
  942.     unit->hp = unit->hp2;
  943.     /* Perhaps adjust the acp down. */
  944.     if (unit->act != NULL
  945.         && unit->act->acp > 0
  946.         && (dameff = u_acp_damage_effect(unit->type)) != lispnil) {
  947.         newacp = damaged_acp(unit, dameff);
  948.         /* The damaged acp limits the remaining acp, rather than trying
  949.            to do some sort of proportional adjustment, which would be
  950.            hard to get right. */
  951.         /* (should account for occupant effects on acp) */
  952.         unit->act->acp = min(unit->act->acp, newacp);
  953.     }
  954.     }
  955.     /* Let the unit's owner know about all this. */
  956.     update_unit_display(unit->side, unit, TRUE);
  957. }
  958.  
  959. /* Retreat is a special kind of movement that a unit uses to avoid
  960.    damage during combat. It bypasses some of the normal move rules. */
  961.  
  962. int
  963. retreat_unit(unit, atker)
  964. Unit *unit, *atker;
  965. {
  966.     int dir;
  967.     extern int retreating_from;
  968.  
  969.     retreating_from = atker->type;
  970.     if (unit->x == atker->x && unit->y == atker->y) {
  971.         dir = random_dir();
  972.     } else {
  973.         dir = approx_dir(unit->x - atker->x, unit->y - atker->y);
  974.     }
  975.     if (retreat_in_dir(unit, dir))
  976.       return TRUE;
  977.     if (flip_coin()) {
  978.         if (retreat_in_dir(unit, left_dir(dir)))
  979.           return TRUE;
  980.         if (retreat_in_dir(unit, right_dir(dir)))
  981.           return TRUE;
  982.     } else {
  983.         if (retreat_in_dir(unit, right_dir(dir)))
  984.           return TRUE;
  985.         if (retreat_in_dir(unit, left_dir(dir)))
  986.           return TRUE;
  987.     }
  988.     retreating_from = NONUTYPE;
  989.     return FALSE;
  990. }
  991.  
  992. int
  993. retreat_in_dir(unit, dir)
  994. Unit *unit;
  995. int dir;
  996. {
  997.     int nx, ny, rslt;
  998.     extern int retreating;
  999.     extern int retreating_from;
  1000.  
  1001.     /* (should it be possible for a unit to retreat out of the world?) */
  1002.     if (!interior_point_in_dir(unit->x, unit->y, dir, &nx, &ny))
  1003.       return FALSE;
  1004.     retreating = TRUE;
  1005.     rslt = check_move_action(unit, unit, nx, ny, unit->z);
  1006.     if (!valid(rslt))
  1007.       return FALSE;
  1008.     do_move_action(unit, unit, nx, ny, unit->z);
  1009.     retreating = FALSE;
  1010.     retreating_from = NONUTYPE;
  1011.     return TRUE;
  1012. }
  1013.  
  1014. /* Capture action. */
  1015.  
  1016. /* Prepare a capture action to be executed later. */
  1017.  
  1018. int
  1019. prep_capture_action(unit, unit2, unit3)
  1020. Unit *unit, *unit2, *unit3;
  1021. {
  1022.     if (unit == NULL || unit->act == NULL)
  1023.       return FALSE;
  1024.     if (unit2 == NULL)
  1025.       return FALSE;
  1026.     unit->act->nextaction.type = A_CAPTURE;
  1027.     unit->act->nextaction.args[0] = unit3->id;
  1028.     unit->act->nextaction.actee = unit2->id;
  1029.     return TRUE;
  1030. }
  1031.  
  1032. /* Execute a capture action. */
  1033.  
  1034. int
  1035. do_capture_action(unit, unit2, unit3)
  1036. Unit *unit, *unit2, *unit3;
  1037. {
  1038.     attempt_to_capture_unit(unit2, unit3);
  1039.     use_up_acp(unit, uu_acp_to_capture(unit2->type, unit3->type));
  1040.     if (unit3->side == unit2->side)
  1041.       return A_ANY_DONE;
  1042.     else
  1043.       /* (should indicate failure of action) */
  1044.       return A_ANY_DONE;
  1045. }
  1046.  
  1047. /* Check the validity of a capture action. */
  1048.  
  1049. int
  1050. check_capture_action(unit, unit2, unit3)
  1051. Unit *unit, *unit2, *unit3;
  1052. {
  1053.     int u, u2, u3, acp, m;
  1054.  
  1055.     if (!in_play(unit))
  1056.       return A_ANY_ERROR;
  1057.     if (!in_play(unit2))
  1058.       return A_ANY_ERROR;
  1059.     if (!in_play(unit3))
  1060.       return A_ANY_ERROR;
  1061.     /* We can't capture ourselves. */
  1062.     if (unit2 == unit3)
  1063.       return A_ANY_ERROR;
  1064.     /* We can't capture units on our side. */
  1065.     if (unit2->side == unit3->side)
  1066.       return A_ANY_ERROR;    
  1067.     u = unit->type;
  1068.     u2 = unit2->type;
  1069.     u3 = unit3->type;
  1070.     acp = uu_acp_to_capture(u2, u3);
  1071.     if (acp < 1)
  1072.       return A_ANY_CANNOT_DO;
  1073.     if (capture_chance(u2, u3, unit3->side) == 0)
  1074.       return A_ANY_CANNOT_DO;
  1075.     if (distance(unit2->x, unit2->y, unit3->x, unit3->y) > 1)
  1076.       return A_ANY_ERROR;
  1077.     if (!has_enough_acp(unit, acp))
  1078.       return A_ANY_NO_ACP;
  1079.     /* We have to have a minimum level of supply to be able to capture. */
  1080.     for_all_material_types(m) {
  1081.     if (unit2->supply[m] < um_to_fight(u2, m))
  1082.       return A_ANY_NO_MATERIAL;
  1083.     }
  1084.     return A_ANY_OK;
  1085. }
  1086.  
  1087. /* Handle capture possibility and repulse/slaughter. */
  1088.  
  1089. /* The chance to capture an enemy is modified by several factors. */
  1090. /* Neutrals have a different chance to be captured, and presence of */
  1091. /* occupants should also has an effect.  Can't capture anything that is */
  1092. /* on a kind of terrain that the capturer can't go on, unless victim has */
  1093. /* "bridge effect". */
  1094.  
  1095. /* (Need a little better treatment of committed assaults, where lack of
  1096.    success == death.) */
  1097.  
  1098. void
  1099. attempt_to_capture_unit(atker, other)
  1100. Unit *atker, *other;
  1101. {
  1102.     int a = atker->type, o = other->type, chance, prot;
  1103.     int ox = other->x, oy = other->y;
  1104.     Unit *occ;
  1105.     Side *as = atker->side, *os = other->side;
  1106.     
  1107.     chance = capture_chance(a, o, other->side);
  1108.     if (alive(atker) && alive(other) && chance > 0) {
  1109.     if (impassable(atker, ox, oy) && !uu_bridge(o, a))
  1110.       return;
  1111.     /* Can possibly detonate on *any* attempt to capture! */
  1112.     if (probability(uu_detonate_on_capture(o, a))) {
  1113.         detonate_unit(other, other->x, other->y, other->z);
  1114.         /* Might not be possible to capture anything anymore. */
  1115.         if (!alive(atker) || !alive(other))
  1116.           return;
  1117.         /* Types of units might have changed, recalc things. */
  1118.         a = atker->type;  o = other->type;
  1119.         as = atker->side;  os = other->side;
  1120.         chance = capture_chance(a, o, other->side);
  1121.     }
  1122.     /* Occupants can protect the transport. */
  1123.     for_all_occupants(other, occ) {
  1124.         if (is_active(occ)) {
  1125.             prot = uu_protection(occ->type, o);
  1126.         chance = (chance * prot) / 100;
  1127.         }
  1128.     }
  1129.     /* Test whether the capture actually happens. */
  1130.     if (probability(chance)) {
  1131.         capture_unit(atker, other);
  1132.     } else if (atker->transport != NULL && 
  1133.            (impassable(atker, ox, oy) ||
  1134.             impassable(atker, atker->x, atker->y))) {
  1135.         /* was the capture attempt a one-way trip? */
  1136.         /* (should fix the test above - needs to be more accurate) */
  1137.         notify(as, "Resistance... %s was slaughtered!",
  1138.            unit_handle(as, atker));
  1139.         notify(os, "Resistance... %s was slaughtered!",
  1140.            unit_handle(os, atker));
  1141.         kill_unit(atker, H_UNIT_KILLED /* should be something appropriate */);
  1142.     } else {
  1143.         /* (should record failed attempt to capture) */
  1144.             char aabuf[BUFSIZE], oabuf[BUFSIZE];
  1145.         
  1146.         strcpy(aabuf, unit_handle(as, atker));
  1147.         notify(as, "%s throws back %s!", unit_handle(as, other), aabuf);
  1148.         strcpy(oabuf, unit_handle(os, atker));
  1149.         notify(os, "%s throws back %s!", unit_handle(os, other), oabuf);
  1150.     }
  1151.     if (chance > 0) {
  1152.         if (atker->cxp < u_cxp_max(a))
  1153.           atker->cxp += uu_cxp_per_capture(a, o);
  1154.         /* (should not increment if side just changed?) */
  1155.         if (other->cxp < u_cxp_max(o))
  1156.           other->cxp += uu_cxp_per_capture(o, a);
  1157.     }
  1158.     }
  1159. }
  1160.  
  1161. int
  1162. capture_chance(u, u2, side2)
  1163. int u, u2;
  1164. Side *side2;
  1165. {
  1166.     int chance, indepchance;
  1167.  
  1168.     chance = uu_capture(u, u2);
  1169.     if (side2 != NULL)
  1170.       return chance;
  1171.     indepchance = uu_indep_capture(u, u2);
  1172.     return (indepchance < 0 ? chance : indepchance);
  1173. }
  1174.  
  1175. /* There are many consequences of a unit being captured.
  1176.    If the capturer is needed as a garrison, unload its occupants first. */
  1177. /* (should reindent) */
  1178. void
  1179. capture_unit(unit, pris)
  1180. Unit *unit, *pris;
  1181. {
  1182.     int u = unit->type, px = pris->x, py = pris->y;
  1183.     Unit *occ;
  1184.     Side *ps = pris->side, *us = unit->side;
  1185.     PastUnit *pastunit;
  1186.  
  1187.     if (probability(uu_scuttle(pris->type, unit->type))) {
  1188.     /* (should add terrain effect on success too) */
  1189.     /* (should characterize as a scuttle) */
  1190.     kill_unit(pris, H_UNIT_DISBANDED);
  1191.     }
  1192.     if (alive(pris)) {
  1193.     pastunit = change_unit_to_past_unit(pris);
  1194.     /* Decide the fate of each occupant of our prisoner. */
  1195.     for_all_occupants(pris, occ) {
  1196.         capture_occupant(unit, pris, occ);
  1197.     }
  1198.     /* The change of side itself.  This happens recursively to any
  1199.        remaining occupants as well. */
  1200.     unit_changes_side(pris, us, H_UNIT_ACQUIRED, H_UNIT_CAPTURED);
  1201.     /* Possibly garrison the newly-captured unit. */
  1202.     /* (should be shared with unit completion code) */
  1203.     if (uu_hp_to_garrison(u, pris->type) > 0) {
  1204.         if (uu_hp_to_garrison(u, pris->type) >= unit->hp) {
  1205.         /* Garrisoning unit will be vanishing, move its occupants out. */
  1206.         for_all_occupants(unit, occ) {
  1207.             if (can_occupy(occ, pris)) {
  1208.             leave_cell(occ);
  1209.             enter_transport(occ, pris);
  1210.             }
  1211.             if (can_occupy_cell(occ, px, py)) {
  1212.             leave_cell(occ);
  1213.             enter_cell(occ, px, py);
  1214.             }
  1215.         }
  1216.         /* This may still kill some of the garrison's occupants, but */
  1217.         /* only under some pretty exotic conditions. */
  1218.         kill_unit(unit, H_UNIT_GARRISONED);
  1219.         } else {
  1220.         unit->hp -= uu_hp_to_garrison(u, pris->type);
  1221.         }
  1222.     }
  1223.     capture_unit_2(unit, pris, pastunit, ps);
  1224.         /* The people at the new location may change sides immediately. */
  1225.         if (people_sides_defined()
  1226.         && any_people_side_changes
  1227.         && probability(people_surrender_chance(pris->type, px, py))) {
  1228.         change_people_side_around(px, py, pris->type, unit->side);
  1229.         }
  1230.     }
  1231.     /* Update everybody's view of the situation. */
  1232.     see_exact(ps, px, py);
  1233.     update_cell_display(ps, px, py, TRUE);
  1234.     all_see_cell(px, py);
  1235. }
  1236.  
  1237. /* Given that the main unit is going to be captured, decide what each occupant
  1238.    will do. */
  1239.  
  1240. void
  1241. capture_occupant(unit, pris, occ)
  1242. Unit *unit, *pris, *occ;
  1243. {
  1244.     int u = unit->type;
  1245.     Unit *subocc;
  1246.  
  1247.     if (probability(uu_occ_escape(u, occ->type))) {
  1248.     /* The occupant escapes, along with all its suboccupants. */
  1249.     /* (should impl by moving to nearby cells?) */
  1250.     } else if (0 /* (should allow for occ scuttling also) */) {
  1251.     } else if (/* u_change_side(occ->type) || */ capture_chance(u, occ->type, occ->side) > 0) {
  1252.     /* Side change will actually happen later. */
  1253.     for_all_occupants(occ, subocc) {
  1254.         capture_occupant(unit, occ, subocc);
  1255.     }
  1256.     } else {
  1257.     /* Occupant can't live as a prisoner, but suboccs might. */
  1258.     for_all_occupants(occ, subocc) {
  1259.         capture_occupant(unit, occ, subocc);
  1260.     }
  1261.     /* Any suboccupants that didn't escape will die. */
  1262.     /* (what if subocc captured tho? should move elsewhere) */
  1263.     kill_unit(occ, H_UNIT_KILLED);
  1264.     }
  1265. }
  1266.  
  1267. static void
  1268. capture_unit_2(unit, pris, pastpris, prevside)
  1269. Unit *unit, *pris;
  1270. PastUnit *pastpris;
  1271. Side *prevside;
  1272. {
  1273.     int observers;
  1274.     Unit *occ;
  1275.  
  1276.     /* Our new unit's experience might be higher or lower, depending on what
  1277.        capture really means (change of crew perhaps). */
  1278.     pris->cxp = (pris->cxp * u_cxp_on_capture(pris->type)) / 100;
  1279.     pris->cxp = min(unit->cxp, u_cxp_max(pris->type));
  1280.     /* Clear any actions and plans. */
  1281.     init_unit_actorstate(pris);
  1282.     init_unit_plan(pris);
  1283.     /* Record for posterity. */
  1284.     observers = NOSIDES;
  1285.     observers = add_side_to_set(unit->side, observers);
  1286.     observers = add_side_to_set(pris->side, observers);
  1287.     observers = add_side_to_set(prevside, observers);
  1288.     record_event(H_UNIT_CAPTURED, observers, unit->id, (pastpris ? pastpris->id : pris->id));
  1289.     /* Likewise for occupants. */
  1290.     for_all_occupants(pris, occ) {
  1291.     capture_unit_2(unit, occ, NULL, prevside);
  1292.     }
  1293. }
  1294.  
  1295. /* A detonate action just blasts the vicinity. */
  1296.  
  1297. int
  1298. prep_detonate_action(unit, unit2, x, y, z)
  1299. Unit *unit, *unit2;
  1300. int x, y, z;
  1301. {
  1302.     if (unit == NULL || unit->act == NULL)
  1303.       return FALSE;
  1304.     if (unit2 == NULL)
  1305.       return FALSE;
  1306.     unit->act->nextaction.type = A_DETONATE;
  1307.     unit->act->nextaction.args[0] = x;
  1308.     unit->act->nextaction.args[1] = y;
  1309.     unit->act->nextaction.args[2] = z;
  1310.     unit->act->nextaction.actee = unit2->id;
  1311.     return TRUE;
  1312. }
  1313.  
  1314. int
  1315. do_detonate_action(unit, unit2, x, y, z)
  1316. Unit *unit, *unit2;
  1317. int x, y, z;
  1318. {
  1319.     int u2 = unit2->type;
  1320.  
  1321.     detonate_unit(unit2, x, y, z);
  1322.     /* Note that if the maxrange is further than the actual range of this
  1323.        detonation, only just-damaged units will be looked at. */
  1324.     reckon_damage_around(x, y, maxudetonaterange);
  1325.     /* Unit might have detonated outside its range, so need this to make
  1326.        its own damage is accounted for. */
  1327.     if (alive(unit2))
  1328.       reckon_damage_around(unit2->x, unit2->y, 0);
  1329.     use_up_acp(unit, u_acp_to_detonate(u2));
  1330.     return A_ANY_DONE;
  1331. }
  1332.  
  1333. int
  1334. check_detonate_action(unit, unit2, x, y, z)
  1335. Unit *unit, *unit2;
  1336. int x, y, z;
  1337. {
  1338.     int u, u2, acp;
  1339.  
  1340.     if (!in_play(unit))
  1341.       return A_ANY_ERROR;
  1342.     if (!in_play(unit2))
  1343.       return A_ANY_ERROR;
  1344.     if (!inside_area(x, y))
  1345.       return A_ANY_ERROR;
  1346.     u = unit->type;
  1347.     u2 = unit2->type;
  1348.     /* The unit must actually be able to detonate. */
  1349.     acp = u_acp_to_detonate(u2);
  1350.     if (acp < 1)
  1351.       return A_ANY_CANNOT_DO;
  1352.     /* Can only detonate in our own or an adjacent cell. */
  1353.     /* (In other words, the detonating unit doesn't get to teleport
  1354.        its detonation effects to any desired faraway location.) */
  1355.     if (distance(unit2->x, unit2->y, x, y) > 1)
  1356.       return A_ANY_ERROR;
  1357.     if (!has_enough_acp(unit, acp))
  1358.       return A_ANY_NO_ACP;
  1359.     return A_ANY_OK;
  1360. }
  1361.  
  1362. static int tmpdetx, tmpdety;
  1363.  
  1364. static void
  1365. detonate_on_cell(x, y)
  1366. int x, y;
  1367. {
  1368.     int dist, dmg, t;
  1369.     Unit *unit2;
  1370.  
  1371.     dist = distance(tmpdetx, tmpdety, x, y);
  1372.     if (dist > 1 && dist <= maxudetonaterange) {
  1373.     for_all_stack(x, y, unit2) {
  1374.         if (dist <= uu_detonation_range(tmpunit->type, unit2->type)) {
  1375.         dmg = uu_detonation_damage_adj(tmpunit->type, unit2->type);
  1376.         /* Reduce by inverse square of the distance. */
  1377.         dmg /= (dist * dist);
  1378.         hit_unit(unit2, dmg, tmpunit);
  1379.         }
  1380.     }
  1381.     }
  1382.     if (dist > 1 && dist <= maxtdetonaterange) {
  1383.     t = terrain_at(x, y);
  1384.     if (probability(ut_detonation_damage(tmpunit->type, t))) {
  1385.         damage_terrain(tmpunit->type, x, y);
  1386.     }
  1387.     }
  1388. }
  1389.  
  1390. /* Actual detonation may occur by explicit action or automatically; this
  1391.    routine makes the detonation effects happen, pyrotechnics and all. */
  1392.  
  1393. /* (need to accumulate a damage report a la regular combat) */
  1394. /* (detonation effect at large distances should be patchy) */
  1395. /* (let elevations screen effects?) */
  1396. /* (interleave visual effects here - hook to display routines) */
  1397. /* (game design should be able to ask for a screen flash as extra) */
  1398.  
  1399. int
  1400. detonate_unit(unit, x, y, z)
  1401. Unit *unit;
  1402. int x, y, z;
  1403. {
  1404.     int u = unit->type, dir, x1, y1, dmg, t, maxrange;
  1405.     Unit *unit2;
  1406.  
  1407.     if (maxudetonaterange < 0) {
  1408.     int u2, u3, range;
  1409.  
  1410.     for_all_unit_types(u2) {
  1411.         for_all_unit_types(u3) {
  1412.         range = uu_detonation_range(u2, u3);
  1413.         maxudetonaterange = max(range, maxudetonaterange);
  1414.         }
  1415.     }
  1416.     }
  1417.     if (maxtdetonaterange < 0) {
  1418.     int u2, t, range;
  1419.  
  1420.     for_all_unit_types(u2) {
  1421.         for_all_terrain_types(t) {
  1422.         range = ut_detonation_range(u2, t);
  1423.         maxtdetonaterange = max(range, maxtdetonaterange);
  1424.         }
  1425.     }
  1426.     }
  1427.     /* Hit the detonating unit first. */
  1428.     hit_unit(unit, u_hp_per_detonation(u), NULL);
  1429.     /* Hit units at ground zero. */
  1430.     for_all_stack(x, y, unit2) {
  1431.         if (unit2 != unit) {
  1432.         hit_unit(unit2, uu_detonation_damage_at(u, unit2->type), unit);
  1433.     }
  1434.     }
  1435.     t = terrain_at(x, y);
  1436.     if (probability(ut_detonation_damage(u, t))) {
  1437.     damage_terrain(u, x, y);
  1438.     }
  1439.     /* Hit units and/or terrain in adjacent cells, if this is defined. */
  1440.     if (maxudetonaterange >= 1) {
  1441.         for_all_directions(dir) {
  1442.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  1443.         for_all_stack(x1, y1, unit2) {
  1444.             dmg = uu_detonation_damage_adj(u, unit2->type);
  1445.             hit_unit(unit2, dmg, unit);
  1446.         }
  1447.         }
  1448.     }
  1449.     }
  1450.     if (maxtdetonaterange >= 1) {
  1451.         for_all_directions(dir) {
  1452.         if (point_in_dir(x, y, dir, &x1, &y1)) {
  1453.         t = terrain_at(x1, y1);
  1454.         if (probability(ut_detonation_damage(u, t))) {
  1455.             damage_terrain(u, x1, y1);
  1456.         }
  1457.         }
  1458.     }
  1459.     }
  1460.     /* Hit units that are further away. */
  1461.     if (maxudetonaterange >= 2) {
  1462.     tmpunit = unit;
  1463.     tmpdetx = x;  tmpdety = y;
  1464.     apply_to_area(x, y, maxudetonaterange, detonate_on_cell);
  1465.     }
  1466.     if (maxtdetonaterange >= 1) {
  1467.         for_all_directions(dir) {
  1468.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  1469.         for_all_stack(x1, y1, unit2) {
  1470.             dmg = uu_detonation_damage_adj(u, unit2->type);
  1471.             hit_unit(unit2, dmg, unit);
  1472.         }
  1473.         }
  1474.     }
  1475.     }
  1476.     maxrange = max(maxudetonaterange, maxtdetonaterange);
  1477.     if (maxrange >= 2) {
  1478.     tmpunit = unit;
  1479.     tmpdetx = x;  tmpdety = y;
  1480.     apply_to_area(x, y, maxrange, detonate_on_cell);
  1481.     }
  1482.     return TRUE;
  1483. }
  1484.  
  1485. void
  1486. damage_terrain(u, x, y)
  1487. int u, x, y;
  1488. {
  1489.     int t, t2, tot, test, sum;
  1490.  
  1491.     t = terrain_at(x, y);
  1492.     tot = 0;
  1493.     for_all_terrain_types(t2) {
  1494.     tot += tt_damaged_type(t, t2);
  1495.     }
  1496.     if (tot > 0) {
  1497.         test = xrandom(tot);
  1498.         sum = 0;
  1499.         for_all_terrain_types(t2) {
  1500.         sum += tt_damaged_type(t, t2);
  1501.         if (test < sum) break;
  1502.         }
  1503.     if (t2 != t) {
  1504.         set_terrain_at(x, y, t2);
  1505.         /* (should inform displays) */
  1506.     }
  1507.     }
  1508. }
  1509.  
  1510. int
  1511. can_attack(unit)
  1512. Unit *unit;
  1513. {
  1514.     return type_can_attack(unit->type);
  1515. }
  1516.  
  1517. int
  1518. type_can_attack(u)
  1519. int u;
  1520. {
  1521.     int u2;
  1522.     
  1523.     for_all_unit_types(u2) {
  1524.     if (uu_acp_to_attack(u, u2) > 0 && uu_hit(u, u2) > 0 && uu_damage(u, u2) > 0)
  1525.       return TRUE;
  1526.     }
  1527.     return FALSE;
  1528. }
  1529.  
  1530. int
  1531. can_fire(unit)
  1532. Unit *unit;
  1533. {
  1534.     return type_can_fire(unit->type);
  1535. }
  1536.  
  1537. int
  1538. type_can_fire(u)
  1539. int u;
  1540. {
  1541.     int u2;
  1542.     
  1543.     if (u_acp_to_fire(u) == 0)
  1544.       return FALSE;
  1545.     for_all_unit_types(u2) {
  1546.     if (uu_hit(u, u2) > 0 && uu_damage(u, u2) > 0)
  1547.       return TRUE;
  1548.     }
  1549.     return FALSE;
  1550. }
  1551.  
  1552. int
  1553. type_can_capture(u)
  1554. int u;
  1555. {
  1556.     int u2;
  1557.     
  1558.     for_all_unit_types(u2) {
  1559.     if (uu_acp_to_capture(u, u2) > 0
  1560.         && (uu_capture(u, u2) > 0 || uu_indep_capture(u, u2) > 0))
  1561.       return TRUE;
  1562.     }
  1563.     return FALSE;
  1564. }
  1565.  
  1566. int
  1567. can_detonate(unit)
  1568. Unit *unit;
  1569. {
  1570.     return (u_acp_to_detonate(unit->type) > 0);
  1571. }
  1572.